package com.ibm.rules;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Range;

/**
 * 
 * @author yaoliang Chen
	 * Key: timeseries's tag index, Value: this tag's rule conditions(ie., Ranges), 
	 *Note that, here use Multimap(google) to map key to a collection of Range, 
	 *and assume that all Range here is concated by "and" relation, so we just need to merge them into a single Range,
	 *merging is to find intersection between all Ranges, and just keep the final intersection(see RuleBuilder#build())
 */
public class RuleBuilder {
	private BigInteger ruleID;
	@SuppressWarnings("rawtypes")
	private Multimap<Integer, Range> entries;
	
	@SuppressWarnings("rawtypes")
	public RuleBuilder(BigInteger ruleID){
		this.ruleID = ruleID;
		this.entries = ArrayListMultimap.<Integer, Range>create();
	}
	
	@SuppressWarnings("rawtypes")
	public RuleBuilder(RuleBuilder rule){
		this.ruleID = rule.getRuleID();
		this.entries = ArrayListMultimap.<Integer, Range>create();
		this.entries.putAll(rule.getEntries());
	}
	
	@SuppressWarnings("rawtypes")
	private Multimap<Integer, Range> getEntries() {
		return entries;
	}

	public BigInteger getRuleID(){
		return ruleID;
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Rule build(){
		Iterator<Entry<Integer, Collection<Range>>> iter = entries.asMap().entrySet().iterator();
		List<RuleEntry> ruleEntries = new ArrayList<>();
		while(iter.hasNext()){
			Entry<Integer, Collection<Range>> entry = iter.next();
			int tagId = entry.getKey();
			Collection<Range> ranges = entry.getValue();
			Iterator<Range> rangeIter = ranges.iterator();
			Range finalRange = null;
			while(rangeIter.hasNext()){
				Range range = rangeIter.next();
				if(finalRange == null){
					finalRange = range;
				} else{
					finalRange = finalRange.intersection(range);
				}
			}
			ruleEntries.add(new RuleEntry(finalRange, tagId));
		}
		RuleEntry[] ruleEntryArray = new RuleEntry[ruleEntries.size()];
		return new Rule(ruleID, ruleEntries.toArray(ruleEntryArray));
	}

	@SuppressWarnings("rawtypes")
	public void addCondition(int tagId, Range  range) {
		entries.put(tagId, range);
	}
}
